package com.whut.service.impl;

import com.whut.common.BaseResponse;
import com.whut.enums.ProjectSampleItemType;
import com.whut.enums.ProjectSampleState;
import com.whut.enums.ProjectSampleType;
import com.whut.mapper.ProjectBuildBasementMapper;
import com.whut.mapper.ProjectMapper;
import com.whut.mapper.ProjectSampleItemMapper;
import com.whut.mapper.ProjectSampleMapper;
import com.whut.model.Project;
import com.whut.model.ProjectBuildBasement;
import com.whut.model.ProjectSample;
import com.whut.model.ProjectSampleItem;
import com.whut.service.ProjectBuildBasementService;
import com.whut.v_bo.ProjectSampleItemSearch;
import com.whut.v_bo.ProjectSampleV3BO;
import com.whut.v_request.ProjectSampleV3ConfirmRequest;
import com.whut.v_request.ProjectSampleV3Request;
import com.whut.v_vo.ProjectSampleV3Response;
import com.whut.v_vo.projectBuildBasement.EditProjectBuildBasementVo;
import com.whut.v_vo.projectBuildBasement.ProjectBuildBasementVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service("/projectBuildBasementService")
public class ProjectBuildBasementServiceImpl implements ProjectBuildBasementService {

    Logger log = LoggerFactory.getLogger(ProjectBuildBasementServiceImpl.class);

    @Resource
    private ProjectBuildBasementMapper projectBuildBasementMapper;

    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private ProjectSampleMapper projectSampleMapper;

    @Resource
    private ProjectSampleItemMapper projectSampleItemMapper;


    /**
     * 根据ID查询
     *
     * @param basementId
     * @return
     */
    @Override
    public BaseResponse findBuildBasementById(Integer basementId) {

        try {

            List<ProjectBuildBasement> buildBasements = projectBuildBasementMapper.findByProjectId(basementId);
            return new BaseResponse(buildBasements);


        } catch (Exception e) {
            log.error("\n根据ID查询地下室工作进度。 ID是：" + basementId);
            log.error("\n错误信息 ： " + e.getMessage());

            return new BaseResponse("查询异常。");
        }

    }

    /**
     * 根据施工项目ID查询地下室工作进度
     *
     * @param projectId 施工项目ID
     * @return
     */
    @Override
    public BaseResponse findBuildBasementsByProjectId(Integer projectId) {

        try {

            List<ProjectBuildBasement> buildBasements = projectBuildBasementMapper.findByProjectId(projectId);
            return new BaseResponse(buildBasements);


        } catch (Exception e) {
            log.error("\n根据施工项目ID查询地下室工作进度。 ID是：" + projectId);
            log.error("\n错误信息 ： " + e.getMessage());

            return new BaseResponse("查询异常。");
        }

    }

    /**
     * 保存地下室施工项目进度信息
     *
     * @param projectBuildBasementVo
     * @return
     */
    @Override
    @Transactional
    public BaseResponse saveBuildBasement(ProjectBuildBasementVo projectBuildBasementVo) {

        try {

            /**
             * 判断楼栋号是否重复
             */
            ProjectBuildBasement buildBasementAndBuild = projectBuildBasementMapper.findByProjectAndBuild(projectBuildBasementVo.getProjectId(), projectBuildBasementVo.getBuild());
            if (Objects.nonNull(buildBasementAndBuild)) {
                return new BaseResponse("楼栋号重复。");
            }

            ProjectBuildBasement projectBuildBasement = new ProjectBuildBasement();
            BeanUtils.copyProperties(projectBuildBasementVo, projectBuildBasement);

            projectBuildBasement.setCreatedTime(LocalDateTime.now());  //创建时间
            projectBuildBasement.setLastModifiedTime(LocalDateTime.now()); //最后修改时间

            projectBuildBasementMapper.save(projectBuildBasement);

            return new BaseResponse(projectBuildBasement);

        } catch (Exception E) {

            log.error("\n添加地下室项目进度失败。");
            log.error("\n错误信息 ： " + E.getMessage());

            return new BaseResponse("添加失败。");

        }

    }

    /**
     * 修改信息
     *
     * @param editProjectBuildBasementVo
     * @return
     */
    @Transactional
    @Override
    public BaseResponse editBuildBasement(EditProjectBuildBasementVo editProjectBuildBasementVo) {

        try {

            if (Objects.isNull(editProjectBuildBasementVo.getBasementId())) {
                return new BaseResponse("非法请求");
            }

            ProjectBuildBasement byProjectAndBuildForEdit = projectBuildBasementMapper.findByProjectAndBuildForEdit(editProjectBuildBasementVo.getProjectId(), editProjectBuildBasementVo.getBuild(), editProjectBuildBasementVo.getBasementId());
            if (Objects.nonNull(byProjectAndBuildForEdit)) {
                return new BaseResponse("楼栋号重复。");
            }

            ProjectBuildBasement projectBuildBasement = projectBuildBasementMapper.findById(editProjectBuildBasementVo.getBasementId());
            BeanUtils.copyProperties(editProjectBuildBasementVo, projectBuildBasement);   //赋值信息进行修改
            projectBuildBasementMapper.modifyById(projectBuildBasement);

            return new BaseResponse(projectBuildBasement);

        } catch (Exception E) {

            log.error("\n修改地下室项目进度失败。");
            log.error("\n错误信息 ： " + E.getMessage());

            return new BaseResponse("修改失败。");

        }

    }

    /**
     * 根据主键删除
     *
     * @param basementId
     * @return
     */
    @Override
    public BaseResponse deleteBuildBasement(Integer basementId) {

        try {

            projectBuildBasementMapper.deleteById(basementId);

            return new BaseResponse();

        } catch (Exception E) {

            log.error("\n删除地下室项目进度失败。 ID是：" + basementId);
            log.error("\n错误信息 ： " + E.getMessage());

            return new BaseResponse("删除异常。");

        }


    }

    /**
     * 地下室抽样
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public BaseResponse projectBuildBasementCheck(ProjectSampleV3Request request) {


        try {

            //项目ID
            Integer projectId = request.getProjectId();
            Project project = Optional.ofNullable(projectMapper.findById(projectId)).orElseThrow(() -> new IllegalArgumentException("项目不存在"));

            //抽样数量
            Integer buildNum = request.getBuildNum();

            List<ProjectSampleItem> projectSampleItemDAOS = new ArrayList<>(buildNum);

            ProjectSampleV3BO query = new ProjectSampleV3BO(project.getId(), ProjectSampleItemType.BUILD_BASEMENT.toString());
            List<ProjectSampleItem> projectSampleItems = projectSampleItemMapper.findByProjectAndType(query);   //查询项目下已经抽样的地下室

            //项目下的所有地下室楼栋
            List<ProjectBuildBasement> projectBuildBasements = Optional.ofNullable(projectBuildBasementMapper.findByProjectId(projectId)).orElseThrow(() -> new IllegalArgumentException("未添加地下室进度信息。"));

            //抽样数量大于楼栋数量
            if (buildNum > projectBuildBasements.size()) {
                return new BaseResponse("抽样库数量不足。");
            }

            //过滤已经抽查的数据
            if (projectSampleItems.size() > 0) {

                projectSampleItems.stream().forEach(projectSampleItem -> {
                    projectBuildBasements.stream()
                            .filter(pro -> pro.getBuild().equals(projectSampleItem.getBuild()))
                            .collect(Collectors.toList());
                });
            }

            ProjectSample sample = new ProjectSample();
            sample.setProjectId(projectId);
            sample.setType(ProjectSampleType.V3);
            sample.setName(String.format("%s-%s-%s", project.getId(), ProjectSampleType.V3.name(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
            sample.setState(ProjectSampleState.Created);
            projectSampleMapper.insert(sample);

            //保存抽样结果
            if (projectBuildBasements.size() >= buildNum) {

                Collections.shuffle(projectBuildBasements);  //打乱顺序 ，取出前 buildNum 条
                List<ProjectBuildBasement> projectBuildBasementResults = projectBuildBasements.subList(0, buildNum);

                //循环添加子集
                projectBuildBasementResults.stream().forEach(projectBuildBasementResult -> {

                    ProjectSampleItem projectSampleItem = new ProjectSampleItem();
                    projectSampleItem.setProjectSampleId(sample.getId());
                    projectSampleItem.setBuild(projectBuildBasementResult.getBuild());
                    projectSampleItem.setType(ProjectSampleItemType.BUILD_BASEMENT);
                    projectSampleItem.setCreatedTime(LocalDateTime.now());
                    projectSampleItem.setLastModifiedTime(LocalDateTime.now());

                    projectSampleItemDAOS.add(projectSampleItem);
                });
            } else {

                //此时出现在过滤已经抽样的数据后，全部过滤完或过滤后的结果集不足以满足需要抽样的数量的情况下
                //此时不做过滤，随机取n条数据
                List<ProjectBuildBasement> basements = projectBuildBasementMapper.findByProjectId(projectId);

                //继续做随机和截断操作
                Collections.shuffle(basements);
                List<ProjectBuildBasement> subBasements = basements.subList(0, buildNum);

                //循环添加子集
                subBasements.stream().forEach(projectBuildBasementResult -> {

                    ProjectSampleItem projectSampleItem = new ProjectSampleItem();
                    projectSampleItem.setProjectSampleId(sample.getId());
                    projectSampleItem.setBuild(projectBuildBasementResult.getBuild());
                    projectSampleItem.setType(ProjectSampleItemType.BUILD_BASEMENT);
                    projectSampleItem.setCreatedTime(LocalDateTime.now());
                    projectSampleItem.setLastModifiedTime(LocalDateTime.now());

                    projectSampleItemDAOS.add(projectSampleItem);
                });

            }
            projectSampleItemMapper.insertBatch(projectSampleItemDAOS);

            return new BaseResponse(Optional.of(projectSampleMapper.getById(sample.getId()))
                    .flatMap(t -> convertV3(t.getId()))
                    .orElseThrow(() -> new RuntimeException("未知异常")));

        } catch (Exception e) {

            log.error("\n地下室抽样异常。");
            log.error("\n错误日志：" + e.getMessage());

            return new BaseResponse("未知异常。");
        }

    }

    /**
     * 确认地下室抽样结果信息
     *
     * @param request
     * @return
     */
    @Override
    @Transactional
    public BaseResponse projectBuildBasementConfirm(ProjectSampleV3ConfirmRequest request) {

        try {

            ProjectSample sample = Optional.ofNullable(projectSampleMapper.getById(request.getSampleId()))
                    .orElseThrow(() -> new IllegalArgumentException("抽样不存在"));
            Assert.isTrue(!ProjectSampleState.Created.equals(sample.getState()), "状态不合法");

            if (request.getModels() != null && !request.getModels().isEmpty()) {
                List<ProjectSampleItem> modifyItems = request.getModels().stream()
                        .map(model -> newProjectItemV3(request.getSampleId(), ProjectSampleItemType.BUILD_BASEMENT,
                                null, model.getId(), null, null)
                        ).collect(Collectors.toList());
                projectSampleItemMapper.deleteBySampleId(request.getSampleId());
                projectSampleItemMapper.insertBatch(modifyItems);
            }

            ProjectSample modifySample = new ProjectSample();
            modifySample.setId(sample.getId());
            modifySample.setState(ProjectSampleState.Confirm);
            modifySample.setRemark1(Optional.ofNullable(request.getRemark()).orElse(""));
            projectSampleMapper.updateById(modifySample);

            return new BaseResponse(Optional.of(projectSampleMapper.getById(sample.getId()))
                    .flatMap(t -> convertV3(t.getId()))
                    .orElseThrow(() -> new RuntimeException("未知异常")));

        } catch (Exception e) {

            log.error("\n确认地下室抽样结果信息异常。");
            log.error("\n错误日志：" + e.getMessage());

            return new BaseResponse("未知异常。");
        }

    }


    private Optional<ProjectSampleV3Response> convertV3(Integer sampleId) {
        return Optional.ofNullable(projectSampleMapper.getById(sampleId))
                .map(t -> {
                    ProjectSampleItemSearch param = new ProjectSampleItemSearch();
                    param.setSampleId(t.getId());
                    List<ProjectSampleItem> items = projectSampleItemMapper.listBySearch(param);
                    ProjectSampleV3Response response = new ProjectSampleV3Response();
                    response.setId(t.getId());
                    response.setName(t.getName());
                    response.setCreatedTime(t.getCreatedTime());
                    response.setModels(convertV3Models(items));
                    response.setRemark(t.getRemark1());
                    return response;
                });
    }

    private List<ProjectSampleV3Response.Build> convertV3Models(List<ProjectSampleItem> items) {

        List<ProjectSampleV3Response.Build> results = new ArrayList<>();

        items.stream().forEach(item -> {
            ProjectSampleV3Response.Build buildName = new ProjectSampleV3Response.Build();
            buildName.setId(item.getBuild());
            buildName.setName(item.getBuild() + "楼栋");
            results.add(buildName);

        });
        return results;
    }

    private ProjectSampleItem newProjectItemV3(Integer sampleId, ProjectSampleItemType type, Integer checkId, String build, Integer floor, Integer family) {
        ProjectSampleItem item = new ProjectSampleItem();
        item.setProjectSampleId(sampleId);
        item.setType(type);
        item.setCheckId(checkId);
        switch (type) {
            case FAMILY:
                item.setFamily(family);
            case FLOOR:
                item.setFloor(floor);
            case BUILD:
                item.setBuild(build);
            case BUILD_BASEMENT:
                item.setBuild(build);
        }
        return item;
    }

}
